/*
 * jopengl_Text.cpp
 *
 *  Created on: 2013-10-31
 *      Author: pan.jinghua
 */

#include <windows.h>
#include <stdio.h>

#include "jopengl_Text.h"
#include "util.h"

#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>
#include <freetype/ftoutln.h>
#include <freetype/fttrigon.h>

void JNICALL Java_jopengl_Text__1create(JNIEnv *env, jobject self, jlong faceAddr,
        jstring value, jint red, jint green, jint blue, jint alpha) {
    FT_Face face = (FT_Face)faceAddr;
    int sizeH = face->size->metrics.height >> 6, baseY = face->size->metrics.ascender >> 6;
    int len = env->GetStringLength(value);
//    printf("1 face %d / %d, %d\n", baseY, sizeH, len);
    const jchar* cv = env->GetStringChars(value, 0);
    FT_Glyph  glyph[len];
    FT_BBox  bbox;
    int w = 0, h = 0, width = 0, height = 0;
    for (int i = 0; i < len; i++) {
        if (cv[i] == '\n') {
            height += sizeH;
            if (w > width) width = w;
            w = 0;
            continue;
        }
        int index = FT_Get_Char_Index(face, cv[i]);
        FT_Load_Glyph(face, index, 0);
        FT_Get_Glyph(face->glyph, &glyph[i]);
        w += glyph[i]->advance.x >> 16;
//        printf("1.%d %lc: %d %d\n", i, (wchar_t)cv[i], height, w);
    }
    height += sizeH;
    if (w > width) width = w;

//    printf("2 create %d x %d\n", width, height);
    byte* data = (byte*)calloc(width * height, 4);
    int x = 0, y = 0, l, t;
    for (int i = 0; i < len; i++) {
        if (cv[i] == '\n') {
            y += sizeH;
            x = 0;
            continue;
        }
        int sizeW = glyph[i]->advance.x >> 16;
        FT_Glyph_Get_CBox(glyph[i], FT_GLYPH_BBOX_PIXELS, &bbox);
        FT_Glyph_To_Bitmap(&glyph[i], FT_RENDER_MODE_NORMAL, NULL, TRUE);
        FT_BitmapGlyph gly = (FT_BitmapGlyph)glyph[i];
        FT_Bitmap bmp = gly->bitmap;
        l = gly->left;
        t = baseY - gly->top;
        w = bmp.width;
        h = bmp.rows;
//        printf("2.%d %d (%d, %d) (%d x %d), ax: %d, mode: %d\n", i, x, l, t, w, h, sizeW, bmp.pixel_mode);
        for (int j = 0; j < h; j++) {
            for (int i = 0; i < w; i++) {
                int offset = ((y + t + j) * width + x + l + i) * 4;
//                printf("%5d : ", offset);
                byte* d = data + offset;
                if (bmp.pixel_mode == FT_PIXEL_MODE_GRAY) {
                    int k = j * bmp.pitch + i;
                    int cl = bmp.buffer[k];
//                    printf("%3d ", cl);
                    d[0] = cl * red / 255;
                    d[1] = cl * green / 255;
                    d[2] = cl * blue / 255;
                    d[3] = cl * alpha / 255;
                } else {
                    int k = j * bmp.pitch + i / 8;
                    int c = bmp.buffer[k] & (0xC0 >> (i % 8));
                    if (c) {
                        d[0] = red;
                        d[1] = green;
                        d[2] = blue;
                        d[3] = 255;
                    } else {
                        d[0]  = d[1] = d[2] = d[3] = 0;
                    }
                }
            }
//            printf("\n");
        }
        x += sizeW;
    }
    jclass clz = env->GetObjectClass(self);
    jfieldID fDataAddr = env->GetFieldID(clz, "dataAddr", "J");
    jfieldID fWidth = env->GetFieldID(clz, "width", "I");
    jfieldID fHeight = env->GetFieldID(clz, "height", "I");
    env->SetLongField(self, fDataAddr, (jlong)data);
    env->SetIntField(self, fWidth, width);
    env->SetIntField(self, fHeight, height);
    env->ReleaseStringChars(value, cv);
    env->DeleteLocalRef(clz);
}

void JNICALL Java_jopengl_Text__1free(JNIEnv *env, jobject self) {
    jclass clz = env->GetObjectClass(self);
    jfieldID fDataAddr = env->GetFieldID(clz, "dataAddr", "J");
    byte* data = (byte*)env->GetLongField(self, fDataAddr);
    delete[] data;
    env->DeleteLocalRef(clz);
}


